﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace JYYQ.BMS
{
    public enum ReceiveMode
    {
        Character,  //字符显示
        Hex,        //十六进制
        Decimal,    //十进制
        Octal,      //八进制
        Binary      //二进制
    }

    public enum SendMode
    {
        Character,  //字符
        Hex         //十六进制
    }

    public partial class MainWindow : Window
    {
        #region Global

        // 接收并显示的方式
        private ReceiveMode receiveMode = ReceiveMode.Hex;

        // 发送的方式
        private SendMode sendMode = SendMode.Character;

        #endregion Global

        #region Event handler for menu items

        private void aboutMenuItem_Click(object sender, RoutedEventArgs e)
        {
            About about = new About();
            about.ShowDialog();
        }

        private void autoSendDataSettingViewMenuItem_Click(object sender, RoutedEventArgs e)
        {
            bool state = autoSendDataSettingViewMenuItem.IsChecked;

            if (state == false)
            {
                autoSendConfigPanel.Visibility = Visibility.Visible;
            }
            else
            {
                autoSendConfigPanel.Visibility = Visibility.Collapsed;
                if (IsCompactViewMode())
                {
                    autoSendConfigPanel.Visibility = Visibility.Visible;
                    EnterCompactViewMode();
                }
            }

            autoSendDataSettingViewMenuItem.IsChecked = !state;
        }

        private void compactViewMenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (IsCompactViewMode())
            {
                RestoreViewMode();
            }
            else
            {
                EnterCompactViewMode();
            }
        }

        private void exitMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void helpMenuItem_Click(object sender, RoutedEventArgs e)
        {
        }

        private void loadConfigMenuItem_Click(object sender, RoutedEventArgs e)
        {
            LoadConfig();
            // 状态栏显示加载成功
            Information("配置信息加载成功。");
        }

        private void saveConfigMenuItem_Click(object sender, RoutedEventArgs e)
        {
            SaveConfig();
            // 状态栏显示保存成功
            Information("配置信息保存成功。");
        }

        private void serialCommunicationSettingViewMenuItem_Click(object sender, RoutedEventArgs e)
        {
            bool state = serialCommunicationSettingViewMenuItem.IsChecked;

            if (state == false)
            {
                serialCommunicationConfigPanel.Visibility = Visibility.Visible;
            }
            else
            {
                serialCommunicationConfigPanel.Visibility = Visibility.Collapsed;

                if (IsCompactViewMode())
                {
                    serialCommunicationConfigPanel.Visibility = Visibility.Visible;
                    EnterCompactViewMode();
                }
            }

            serialCommunicationSettingViewMenuItem.IsChecked = !state;
        }

        private void serialSettingViewMenuItem_Click(object sender, RoutedEventArgs e)
        {
            bool state = serialSettingViewMenuItem.IsChecked;

            if (state == false)
            {
                serialPortConfigPanel.Visibility = Visibility.Visible;
            }
            else
            {
                serialPortConfigPanel.Visibility = Visibility.Collapsed;
                if (IsCompactViewMode())
                {
                    serialPortConfigPanel.Visibility = Visibility.Visible;
                    EnterCompactViewMode();
                }
            }

            serialSettingViewMenuItem.IsChecked = !state;
        }

        #endregion Event handler for menu items

        #region Event handler for buttons and so on.

        private void clearRecvDataBoxButton_Click(object sender, RoutedEventArgs e)
        {
            recvDataDataGrid.ItemsSource = null;
        }

        private void drawDataButton_Click(object sender, RoutedEventArgs e)
        {
            IList<ChargeData> CData = (List<ChargeData>)this.recvDataDataGrid.ItemsSource;
            DataCurve drawWindow = new DataCurve(CData);

            drawWindow.ShowDialog();
        }

        private void findPortButton_Click(object sender, RoutedEventArgs e)
        {
            FindPorts();
        }

        private void importData()
        {
            string filePath = FileDialogHelper.GetOpenFilePath();
            DataTable dt = ExcelHelper.Import(filePath);

            IList<ChargeData> list = DataTableHelper.ConvertToList<ChargeData>(dt);
            this.recvDataDataGrid.ItemsSource = list;
        }

        private void importDataButton_Click(object sender, RoutedEventArgs e)
        {
            importData();
        }

        private void openClosePortButton_Click(object sender, RoutedEventArgs e)
        {
            if (serialPort.IsOpen)
            {
                if (ClosePort())
                {
                    openClosePortButton.Content = "打开";
                }
            }
            else
            {
                if (OpenPort())
                {
                    openClosePortButton.Content = "关闭";
                }
            }
        }

        private void recvModeButton_Checked(object sender, RoutedEventArgs e)
        {
            RadioButton rb = sender as RadioButton;

            if (recvDataDataGrid == null)
            {
                Information("当前没有数据");
                return;
            }

            if (rb != null)
            {
                //
                // TO-DO:
                // 可以将已经存在在文本框中的内容全部转换成指定形式显示，而不是简单地清空
                //
                recvDataDataGrid.Items.Clear();

                switch (rb.Tag.ToString())
                {
                    case "char":
                        receiveMode = ReceiveMode.Character;
                        Information("提示：字符显示模式。");
                        break;

                    case "hex":
                        receiveMode = ReceiveMode.Hex;
                        Information("提示：十六进制显示模式。");
                        break;

                    case "dec":
                        receiveMode = ReceiveMode.Decimal;
                        Information("提示：十进制显示模式。");
                        break;

                    case "oct":
                        receiveMode = ReceiveMode.Octal;
                        Information("提示：八进制显示模式。");
                        break;

                    case "bin":
                        receiveMode = ReceiveMode.Binary;
                        Information("提示：二进制显示模式。");
                        break;

                    default:
                        break;
                }
            }
        }

        private void saveRecvDataButton_Click(object sender, RoutedEventArgs e)
        {
            saveRecvData();
        }

        private void sendDataButton_Click(object sender, RoutedEventArgs e)
        {
            SendData();
        }

        //private void appendRadioButton_Click(object sender, RoutedEventArgs e)
        //{
        //    RadioButton rb = sender as RadioButton;
        //    if (rb != null)
        //    {
        //        switch (rb.Tag.ToString())
        //        {
        //            case "none":
        //                appendContent = "";
        //                break;
        //            case "return":
        //                appendContent = "\r";
        //                break;
        //            case "newline":
        //                appendContent = "\n";
        //                break;
        //            case "retnewline":
        //                appendContent = "\r\n";
        //                break;
        //            default:
        //                break;
        //        }
        //        Information("发送追加：" + rb.Content.ToString());
        //    }
        //}

        #endregion Event handler for buttons and so on.

        #region Event handler for timers

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AutoSendDataTimer_Tick(object sender, EventArgs e)
        {
            bool ret = false;
            ret = SendData();

            if (ret == false)
            {
                StopAutoSendDataTimer();
            }
        }

        private void ClockTimer_Tick(object sender, EventArgs e)
        {
            UpdateTimeDate();
        }

        private void saveRecvData()
        {
            List<ChargeData> data = (List<ChargeData>)recvDataDataGrid.ItemsSource;
            if (data == null)
            {
                Information("没有数据！");
                return;
            }

            DataTable dt = DataTableHelper.ConvertToDataTable(data);
            string filePath = FileDialogHelper.GetSaveFilePath();
            ExcelHelper.Export(dt, "Data", filePath);
        }

        /// <summary>
        /// 窗口关闭前拦截
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // 释放没有关闭的端口资源
            if (serialPort.IsOpen)
            {
                ClosePort();
            }

            // 提示是否需要保存配置到文件中
            if (MessageBox.Show("是否在退出前保存软件配置？", "小贴士", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
            {
                SaveConfig();
            }
        }

        /// <summary>
        /// 捕获窗口按键。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            // Ctrl+S保存数据
            if (e.Key == Key.S && e.KeyboardDevice.IsKeyDown(Key.LeftCtrl))
            {
                saveRecvData();
            }

            // Ctrl+Enter 进入/退出简洁视图模式
            if (e.Key == Key.Enter && e.KeyboardDevice.IsKeyDown(Key.LeftCtrl))
            {
                if (IsCompactViewMode())
                {
                    RestoreViewMode();
                }
                else
                {
                    EnterCompactViewMode();
                }
            }

            // Enter发送数据
            if (e.Key == Key.Enter)
            {
                SendData();
            }
        }

        #endregion Event handler for timers

        #region EventHandler for serialPort

        // 数据接收缓冲区
        private List<byte> receiveBuffer = new List<byte>();

        private void BindData(byte[] buffer)
        {
            battery.BType = (BatteryType)Convert.ToUInt32(buffer[2]);//电池的类型
            battery.BStandVolage = Convert.ToDouble((buffer[4] << 8) + buffer[3]) / 10.0;//电池的标称电压
            battery.BCapcity = Convert.ToDouble((buffer[6] << 8) + buffer[5]) / 10.0;//电池的标准容量
            battery.BLevel = Convert.ToInt32(buffer[7]);//电池的级别
            battery.BTime = new DateTime(2016, 5, 23, 21, 2, 12);

            IList<ChargeData> DList = new List<ChargeData>();
            int index = 8;
            for (int i = 0; i < (buffer.Length - 8) / 6; i++)
            {
                ChargeData CData = new ChargeData();
                CData.Hour = Convert.ToInt32(buffer[index]);//小时
                CData.Minute = Convert.ToInt32(buffer[index + 1]);//分钟
                CData.Voltage = Convert.ToDouble((buffer[index + 3] << 8) + buffer[index + 2]) / 10.0;//实时电压
                CData.Current = Convert.ToDouble((buffer[index + 5] << 8) + buffer[index + 4]) / 10.0;//实时电流
                DList.Add(CData);
                index += 6;
            }
            battery.BData = DList;
            this.Dispatcher.Invoke(new Action(() =>
            {
                recvDataDataGrid.ItemsSource = battery.BData;
                recvDesTextBlock.DataContext = battery;
            }));
        }

        private void HandleData(byte[] buffer)
        {
        }

        /// <summary>
        /// 更新：采用一个缓冲区，当有数据到达时，把字节读取出来暂存到缓冲区中，缓冲区到达定值
        /// 时，在显示区显示数据即可。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.IO.Ports.SerialPort sp = sender as System.IO.Ports.SerialPort;
            Thread.Sleep(3000);
            int bytesToRead = sp.BytesToRead;
            byte[] tempBuffer = new byte[bytesToRead]; // 临时缓冲区将保存串口缓冲区的所有数据
            sp.Read(tempBuffer, 0, bytesToRead);  // 将缓冲区所有字节读取出来
            receiveBuffer.AddRange(tempBuffer); // 暂存缓冲区字节到全局缓冲区中等待处理

            if (portSate == PortState.ReadVoltage)
            {
                HandleVolatageData(receiveBuffer.ToArray());
                receiveBuffer.Clear();
            }
            else if (portSate == PortState.SetValtage)
            {
                receiveBuffer.Clear();
                return;
            }
            else
            {
                if (IsNullData(receiveBuffer.ToArray()))
                {
                    receiveBuffer.Clear();
                    return;
                }

                while (receiveBuffer.Count >= 8)
                {
                    HandleData(receiveBuffer.ToArray());
                }

                BindData(receiveBuffer.ToArray());
            }
        }

        #endregion EventHandler for serialPort

        #region 数据处理

        /// <summary>
        /// 判断是否电压值
        /// </summary>
        /// <param name="buff"></param>
        /// <returns></returns>
        private void HandleVolatageData(byte[] buff)
        {
            string str = Encoding.Default.GetString(buff);
            if (str.Length == 7 && str.Contains("$V") && str.Contains("*"))
            {
                this.Dispatcher.Invoke(new Action(
                      () =>
                      {
                          MessageBox.Show(string.Format("当前基准电压为:{0} 伏", str.Substring(2, 4), "基准电压")); ;
                      }
                      ));
            }
        }

        /// <summary>
        /// 判断有无数据
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private bool IsNullData(byte[] buffer)
        {
            for (int i = 0; i < nonByteData.Length; i++)
            {
                if (buffer[i] != nonByteData[i])
                {
                    return false;
                }
            }
            this.Dispatcher.Invoke(new Action(() =>
            {
                MessageBox.Show("没有更多的数据可以接收了！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }));
            return true;
        }

        #endregion 数据处理
    }
}